/*  Copyright 2010 Daniel Brasil Magnani
 *  Created on: Dec 20, 2010
 *  Author: daniel */

#include "instance.h"

using ::std::vector;

int Instance::Init(char *instance_name, int source, int priority) {
  char temp_string[256];
  FILE *instances_map; 
  instances_map = fopen("instances/instances_map", "r");
  while ( fscanf(instances_map, "%s", temp_string) > 0 ) {
    if ( strcmp(instance_name, temp_string) == 0 ) {
      fscanf(instances_map, "%s", temp_string);
      strcpy(instance_name_, temp_string);
      fclose(instances_map);
      break;
    } else {
      fscanf(instances_map, " %*s\n");
    }
  }
  if ( source == 1 ) {
    ReadPaintInput();
    ReadConstraints(priority);
    ReadVehicles(priority);
  } else {
    ReadCSPInput();
    GenerateFiles();
  }

  return true;
}

int Instance::GenerateFiles() {
  FILE *temp_file;
  char temp_string[256];

  sprintf(temp_string, "base_instances/solver/%s\0", instance_name_);
  mkdir(temp_string, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  sprintf(temp_string, "base_instances/solver/%s/paint_batch_limit.txt\0",
          instance_name_);
  temp_file = fopen(temp_string, "w");
  fprintf(temp_file, "limitation;\n500\n");
  fclose(temp_file);

  sprintf(temp_string, "base_instances/solver/%s/optimization_objectives.txt\0",
          instance_name_);
  temp_file = fopen(temp_string, "w");
  fprintf(temp_file, "rank;objective name;\n");
  fprintf(temp_file,
          "1;high_priority_level_and_easy_to_satisfy_ratio_constraints;\n");
  fprintf(temp_file, "2;low_priority_level_ratio_constraints;\n");
  fprintf(temp_file, "3;paint_color_batches;");
  fclose(temp_file);

  sprintf(temp_string, "base_instances/solver/%s/ratios.txt\0", instance_name_);
  temp_file = fopen(temp_string, "w");
  fprintf(temp_file, "Ratio;Prio;Ident;\n");
  for ( int i = 0; i < constraint_list_.size(); i++ ) {
    fprintf(temp_file, "%d/%d;1;HPRC%d;\n", constraint_list_[i].n,
            constraint_list_[i].p, i+1);
  }
  fclose(temp_file);

  sprintf(temp_string, "base_instances/solver/%s/vehicles.txt\0",
          instance_name_);
  temp_file = fopen(temp_string, "w");
  fprintf(temp_file, "Date;SeqRank;Ident;Paint Color;");
  for ( int i = 0; i < constraint_list_.size(); i++ ) {
    fprintf(temp_file, "HPRC%d;", i+1);
  }
  fprintf(temp_file, "\n");
  for ( int i = 0; i < yesterday_cars_.size(); i++ ) {
    fprintf(temp_file, "2011 1 1;1;%d;1;", (int)(today_cars_.size()+i));
    for ( int j = 0; j < constraint_list_.size(); j++ ) {
      fprintf(temp_file, "0;");
    }
    fprintf(temp_file, "\n");
  }
  for ( int i = 0; i < today_cars_.size(); i++ ) {
    fprintf(temp_file, "2011 1 2;1;%d;1;", i);
    for ( int j = 0; j < constraint_list_.size(); j++ )
      fprintf(temp_file, "%d;", today_cars_[i].constraints[j]);
    fprintf(temp_file, "\n");
  }
  fclose(temp_file);

  return true;
}
int Instance::ReadCSPInput() {
  char temp_string[256];
  FILE *base_input;
  sprintf(temp_string, "base_instances/%s\0", instance_name_);
  base_input = fopen(temp_string, "r");
  if ( base_input == NULL )
    return false;
  int num_constraints, num_lines;
  fscanf(base_input, "%*d %d %d\n", &num_constraints, &num_lines);
  Constraint temp_constraint;
  Car temp_car;
  int temp_int;
  int max_constraint = 0;
  //temp_car.identifier = new char[80];
  temp_car.identifier = 0;
  for ( int i = 0; i < num_constraints; i++ ) {
    fscanf(base_input, "%d", &(temp_constraint.n));
    constraint_list_.push_back(temp_constraint);
  }
  for ( int i = 0; i < num_constraints; i++ ) {
    fscanf(base_input, "%d", &(constraint_list_[i].p));
    if ( constraint_list_[i].p > max_constraint )
      max_constraint = constraint_list_[i].p;
  }
  for ( int i = 0; i < max_constraint; i++ ) {
    temp_car.constraints = new int[num_constraints];
    for ( int j = 0; j < num_constraints; j++ )
      temp_car.constraints[j] = 0;
    yesterday_cars_.push_back(temp_car);
  }
  for ( int i = 0; i < num_lines; i++ ) {
    fscanf(base_input, "%*d %d ", &temp_int);
    temp_car.constraints = new int[num_constraints];
    for ( int j = 0; j < num_constraints; j++ ) {
      fscanf(base_input, "%d", &(temp_car.constraints[j]));
    }
    for ( int j = 0; j < temp_int; j++ ) {
//      sprintf(temp_car.identifier, "%d\0", today_cars_.size());
      temp_car.identifier = today_cars_.size();   
      today_cars_.push_back(temp_car);
    }
  }

  fclose(base_input);
  return 1;
}

int Instance::ReadPaintInput() {
  char temp_string[256];
  FILE *paint_limit_input;
  sprintf(temp_string, "instances/%s/paint_batch_limit.txt\0", instance_name_);

  paint_limit_input = fopen(temp_string, "r");
  if ( paint_limit_input == NULL )
    return false;

  fscanf(paint_limit_input, "%*s\n%d;\n", &paint_batch_limit_);
  fclose(paint_limit_input);
  return true;
}

int Instance::ReadConstraints(int priority) {
  int n, p;
  int temp_priority;
  char temp_string[256];
  FILE *ratio_input;
  num_hprc_ = 0;
  num_lprc_ = 0;
  sprintf(temp_string, "instances/%s/ratios.txt\0", instance_name_);
  ratio_input = fopen(temp_string, "r");
  if ( ratio_input == NULL )
    return false;
  Constraint temp_constraint;
  fscanf(ratio_input, "%*s\n");
  while ( fscanf(ratio_input, "%d/%d;%d;%*s\n", &n, &p, &temp_priority) > 0 ) {
    temp_constraint.n = n;
    temp_constraint.p = p;
    if ( temp_priority == 1 ) {
      num_hprc_++;
      if ( priority == 1 )
        constraint_list_.push_back(temp_constraint);
    } else {
      num_lprc_++;
      if ( priority == 0 )
        constraint_list_.push_back(temp_constraint);
    }
  }
  fclose(ratio_input);
  return true;
}

int Instance::ReadVehicles(int priority) {
  int date;
  int date_before = 0;
  int date_change = 0;
  int64_t identifier;
  Car temp_car;
  int temp_int;

  FILE *vehicles_input;
  char temp_string[256];
  sprintf(temp_string, "instances/%s/vehicles.txt\0", instance_name_);
  vehicles_input = fopen(temp_string, "r");
  if ( vehicles_input == NULL )
    return false;
  fscanf(vehicles_input, "%*s%*s\n");
  while ( fscanf(vehicles_input, "%*s%*s%d;%*d;%lld;%*d;",
                 &date, (long long int*)(&identifier)) > 0 ) {
    temp_car.identifier = identifier;
    if ( priority ) 
      temp_car.constraints = new int[num_hprc_];
    else
      temp_car.constraints = new int[num_lprc_];

    if ( (date != date_before && date_before != 0) )
      date_change = 1;

    if ( priority ) {
      for ( int i = 0; i < num_hprc_ ; i++ ) {
        fscanf(vehicles_input, "%d;", &temp_int);
        if ( temp_int ) {
          temp_car.constraints[i] = 1;
        } else {
          temp_car.constraints[i] = 0;
        }
      }
      if ( num_lprc_ > 0 )
        fscanf(vehicles_input, "%*s\n");
    } else {
      for ( int i = 0; i < num_hprc_ ; i++ )
        fscanf(vehicles_input, "%*d;");
      for ( int i = 0; i < num_lprc_ ; i++ ) {
        fscanf(vehicles_input, "%d;", &temp_int);
        if ( temp_int ) {
          temp_car.constraints[i] = 1;
        } else {
          temp_car.constraints[i] = 0;
        }
      }
    }

    if ( date_change == 0 )
      yesterday_cars_.push_back(temp_car);
    else
      today_cars_.push_back(temp_car);

    date_before = date;
  }
  fclose(vehicles_input);
  return true;
}

int Instance::WriteOutput(const vector<Car>& solution) {
  FILE *output;
  char temp_string[256];
  sprintf(temp_string, "outputs/%s\0", instance_name_);
  output = fopen(temp_string, "w");
  if ( output == NULL )
    return false;

  for ( int i = yesterday_cars_.size(); i < (solution.size() - yesterday_cars_.size()); i++ ) {
    fprintf(output, "%d;%lld\n",
            (int)(i-yesterday_cars_.size()+1),
            (long long int)(solution[i].identifier));
  }


  fclose(output);
  return true;
}

char* Instance::get_instance_name() {
  return instance_name_;
}

int Instance::get_paint_batch_limit() {
  return paint_batch_limit_;
}

const vector<Car>& Instance::get_yesterday_cars() {
  return yesterday_cars_;
}

const vector<Car>& Instance::get_today_cars() {
  return today_cars_;
}

const vector<Constraint>& Instance::get_constraint_list() {
  return constraint_list_;
}
